#include "StdAfx.h"
#include "DxRenderer.h"
#include "Utility\Vector4.h"
#include "GeometryInstance.h"
#include "DxVertexBuffer.h"
#include "DxIndexBuffer.h"
#include "DxVertexShader.h"
#include "DxPixelShader.h"
#include "DxShaderManager.h"
#include "DxTexture.h"

DxRenderer* DxRenderer::sm_pRenderer = 0;

DxRenderer::DxRenderer(void)
{
	m_pDevice = NULL;
	m_pD3D = NULL;

	
}


DxRenderer::~DxRenderer(void)
{
	if( m_pDevice != NULL)
        m_pDevice->Release();

    if( m_pD3D != NULL)
        m_pD3D->Release();
}

/**
 * Create the DirectX3D 9 Device
 * BRF 05/04/11
 **/
bool DxRenderer::CreateDevice(HWND hWnd)
{
	if( NULL == (m_pD3D = Direct3DCreate9(D3D_SDK_VERSION) ) )
		return false;

	D3DPRESENT_PARAMETERS d3dpp; 
	ZeroMemory( &d3dpp, sizeof(d3dpp) );
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
	d3dpp.EnableAutoDepthStencil = TRUE;


	if( FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                  &d3dpp, &m_pDevice ) )) 
								  return false;
	RECT rect;
	GetClientRect(hWnd, &rect);

	m_fScreenWidth = rect.right - rect.left;
	m_fScreenHeight = rect.bottom - rect.top;

	m_pDevice->SetRenderState( D3DRS_CULLMODE, 1 );

	return true;
}

/**
 * Start the renderering of the scene
 * BRF 05/04/11
 **/
void DxRenderer::BeginDraw()
{
	// Clear the back buffer to a blue color
	m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,  D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
	m_pDevice->BeginScene();
}

/**
 * Finish the draw and present the scene
 * BRF 05/04/11
 **/
void DxRenderer::EndDraw()
{
	m_pDevice->EndScene();
	m_pDevice->Present(NULL, NULL, NULL, NULL);
}

/**
 * Draw the geometry instance
 * BRF 05/10/11
 **/
void DxRenderer::DrawGeometry(Geometry* geometry, const Matrix& mWorld)
{
	DxVertexBuffer* vb = geometry->GetVertexBuffer();
	DxVertexShader* pDefaultVS = DxShaderManager::GetInstance()->GetDefaultVS();

	m_pDevice->SetVertexDeclaration(vb->GetVertexDecleration());
	m_pDevice->SetVertexShader(pDefaultVS->GetD3DVertexShader());
    m_pDevice->SetStreamSource(0, vb->GetBuffer(), 0, vb->GetStride());
	m_pDevice->SetIndices(geometry->GetIndexBuffer()->GetBuffer());
	
	SetShaderWorld(mWorld);
	SetShaderWorldViewProjection();
	
	m_pDevice->SetPixelShader(DxShaderManager::GetInstance()->GetDefaultPS()->GetD3DPixelShader());
	m_pDevice->SetTexture(0, geometry->GetTexture()->GetDxTexture());

	m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vb->GetVertexCount(), 0, geometry->GetIndexBuffer()->GetPrimativeCount());
}

void DxRenderer::SetWorld(const Matrix& mWorld)
{
	m_mWorldViewProjection = mWorld * m_mView * m_mProjection;
}

void DxRenderer::SetView(const Matrix& mView)
{
	m_mView = mView;
}

void DxRenderer::SetPerspective(float fFov, float fNear, float fFar)
{
	m_mProjection.Perspective(fFov, m_fScreenWidth / m_fScreenHeight, fNear, fFar);
}

bool DxRenderer::SetShaderWorldViewProjection()
{
	bool bRet = false;

	Matrix mTranspose = m_mWorldViewProjection;
	mTranspose.Transpose();
	bRet = GetDevice()->SetVertexShaderConstantF(c0, (float*)&mTranspose, 4)  == D3D_OK ;	

	return bRet;

}

bool DxRenderer::SetShaderWorld(const Matrix& mWorld)
{
	bool bRet = false;

	Matrix mTranspose = mWorld;
	mTranspose.Transpose();
	bRet = GetDevice()->SetVertexShaderConstantF(c4, (float*)&mTranspose, 4)  == D3D_OK ;	

	return bRet;
}
